﻿using Kamahl.Common;
using KonachanChanger.API;
using KonachanChanger.Data;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading;
using System.Windows.Forms;

namespace KonachanChanger
{
    static class Program
    {
        static FileInfo _logFile;

        //[Obsolete]
        //public static string SavePath
        //{
        //    get
        //    {
        //        return UserPrefs.GetInstance().SavePathS;
        //    }
        //}

        public static void Log(string info, params object[] args)
        {
            Log(String.Format(info, args));
        }

        public static void Log(string info)
        {
            info = String.Format("{0}: {1}", DateTime.Now.ToShortTimeString(), info);
            Console.WriteLine(info);
            lock (_logFile)
                File.AppendAllLines("log.txt", new string[] { info });
        }
        private static void Cleanup(object blah)
        {
            var local = LocalDb.GetInstance();
            Thread.CurrentThread.Name = "Cleanup";
            Log("Starting Background work");
            // Start by nuking Obviously failed Thumbnails.
            foreach (var thumb in new DirectoryInfo(".thumbnails").EnumerateFiles("*", SearchOption.AllDirectories))
            {
                if (thumb.Length < 1024) // Not even thumbnails are smaller than 1KB.
                {
                    try
                    {
                        thumb.Delete();
                        Log("Background: Deleted thumbnail {0} due to small size", thumb);
                    }
                    catch (IOException) { }
                }
            }
            foreach (var thumb in new DirectoryInfo(".thumbnails").EnumerateFiles("*", SearchOption.TopDirectoryOnly))
            {
                post p = local.LocalSearch(String.Concat("md5:", Path.GetFileNameWithoutExtension(thumb.Name))).Posts.FirstOrDefault() as post;
                if (p != null)
                {
                    Log("Moving thumbnail {0} into rating folder {1}", thumb.Name, p.rating);
                    thumb.MoveTo(Path.Combine(".thumbnails", p.rating, thumb.Name));
                }
            }
            // Then Download all missing thumbnails in the Db.
            if (local.Prefs.BackgroundGetThumbs)
                GetMissingThumbs(local);
            //Organize Walls into subfolders based on 'favorite' tags.
            if (local.Prefs.BackgroundSort)
                SortLocalFolders(local);
            if (local.Prefs.BackgroundCheckTagMes)
                RecheckTagMes(local);
            CountLocalTags(local);
            // And now the big one; Start caching all the wallpapers.
            if (local.Prefs.BackgroundGetAllWalls)
                foreach (var post in local.AllPosts)
                {
                    try
                    {
                        post.Download();
                    }
                    catch (WebException) { }
                }
            Log("Background: Finished");
        }

        private static void CountLocalTags(LocalDb local)
        {
            var counts = new Dictionary<string, int>();
            foreach (var post in local.AllPosts)
            {
                var tags = post.Tags;
                foreach (var t in tags)
                {
                    if (!counts.ContainsKey(t))
                        counts[t] = 0;
                    counts[t]++;
                }
            }
            foreach (var tag in counts)
            {
                try
                {
                    API.TagCollection.TagInfo taginfo;
                    if (!local.Tags.ContainsKey(tag.Key))
                    {
                        taginfo = API.TagCollection.LoadTagInfo(tag.Key).FirstOrDefault(n => n.Name == tag.Key);
                    }
                    else
                    {
                        taginfo = local.Tags[tag.Key];
                        if (taginfo.Name == null)
                            taginfo = API.TagCollection.LoadTagInfo(tag.Key).FirstOrDefault(n => n.Name == tag.Key);
                    }
                    local.SetTagData(new API.TagCollection.TagInfo()
                    {
                        Name = taginfo.Name,
                        Count = taginfo.Count,
                        Type = taginfo.Type,
                        LocalCount = tag.Value
                    });
                }
                catch (WebException)
                { }
            }
            var poptags = counts.OrderByDescending(t => t.Value).Select(t => t.Key).ToArray();
            foreach (var p in poptags)
            {
                if (!local.Tags.ContainsKey(p))
                    continue;
                var info = local.Tags[p];
                if (info.Type == API.TagCollection.TagType.copyright)
                {
                    if (info.LocalCount > 150 && !local.FavoriteTags.Contains(p))
                        local.AddFavoriteTag(p);
                }
            }

        }

        static void CurrentDomain_FirstChanceException(object sender, System.Runtime.ExceptionServices.FirstChanceExceptionEventArgs e)
        {
            Log("FCException:  \n{0}", e.Exception);
        }

        static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            MessageBox.Show(e.ExceptionObject.ToString());
            Log("UHException:  \n{0}", e.ExceptionObject);
            //MessageBox.Show(e.ExceptionObject.ToString());
        }

        private static void GetMissingThumbs(LocalDb local)
        {
            foreach (var post in local.AllPosts)
            {
                string img = post.ThumbnailPathLocal();
                if (!File.Exists(img))
                {
                    Log("Background: Downloading thumbnail {0}", img);
                    try
                    {
                        var content = new WebClient().DownloadData(new Uri(post.preview_url));
                        File.WriteAllBytes(img, content);
                    }
                    catch (WebException)
                    {

                    }
                }
            }
        }

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main(string[] args)
        {
            AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;

            //System.Diagnostics.Debugger.Launch();
            foreach (string r in new string[] { "s", "q", "e" })
            {
                //Directory.CreateDirectory(SavePath(r));
                //Directory.CreateDirectory(Path.Combine(SavePath(r), ".thumbnails")); 
                Directory.CreateDirectory(Path.Combine(SavePath(r), ".thumbnails", r)); // This creates the first two by default.
            }
            Environment.CurrentDirectory = SavePath("s");
           _logFile = new FileInfo("log.txt");
            File.WriteAllText("log.txt", "");
            Application.SetCompatibleTextRenderingDefault(false); 
            Application.EnableVisualStyles();
            //AppDomain.CurrentDomain.FirstChanceException += CurrentDomain_FirstChanceException;
            if (args.Length > 0)
            {
                if (File.Exists(args[0]) && Path.GetExtension(args[0]) == ".kcc")
                    LocalDb.GetInstance().Prefs.LastSearch = File.ReadAllText(args[0]).Trim('\r', '\n');
                else if (args[0] == "-cleanup")
                {
                    Cleanup(null);
                    return;
                }
            }
            ThreadPool.QueueUserWorkItem(Cleanup);
            if (UserPrefs.GetInstance().EnableP2P)
            {
                var p2p = Extensions.P2P.P2PCore.Instance;
                p2p.Init();
            }
            Application.Run(new Form1());
        }
        private static void RecheckTagMes(LocalDb local)
        {
            try
            {
                foreach (var post in local.LocalSearch("tagme").CastedPosts())
                {
                    Log("Background:  Getting updated data for image id:{0}", post.id);
                    Search s = new Search();
                    s.tags = "id:" + post.id;
                    s.ShouldCacheSearch = false;
                    var upd = s.getPosts().CastedPosts().FirstOrDefault();
                    if (upd == null)
                        Log("Background:  id:{0} has been removed?", post.id);
                    else if (upd.Tags.Contains("tagme"))
                        Log("Background:  id:{0} still has tagme", post.id);
                    else
                        Log("Background:  id:{0} has been tagged", post.id);
                }
            }
            catch (WebException)
            {

            }
        }

        private static void SortLocalFolders(LocalDb local)
        {
            foreach (var tag in local.FavoriteTags)
            {
                //Directory.CreateDirectory(Path.Combine(SavePath, tag));
            }
            foreach (var post in local.AllPosts)
            {
                var tags = post.Tags;
                var fav = post.FavoriteTag;
                if (!string.IsNullOrEmpty(fav))
                {
                    string source;
                    try
                    {
                        source = post.Download();
                    }
                    catch (WebException)
                    { continue; }
                    catch (InvalidDataException)
                    {
                        continue;
                    }
                    string dest;
                    if (!Directory.Exists(Path.Combine(SavePath(post.Rating), fav)))
                        Directory.CreateDirectory(Path.Combine(SavePath(post.Rating), fav));
                    if (!File.Exists(dest = Path.Combine(SavePath(post.Rating), fav, post.md5 + post.FileExtension)))
                    {
                        Log("Putting {0} into favorite folder {1}", post.md5, fav);
                        try
                        {
                            //if (Path.GetDirectoryName(source) == Program.SavePath)
                                File.Move(source, dest);
                        }
                        catch (WebException v)
                        {
                            Log("Unable to download {0}.\n\t{1}", post.md5, v.Message);
                        }
                    }
                    else if (source != dest)
                    {
                        // Duplicate?
                        Log("Background: {0} exists in both {1} and {2}", post.id, source, dest);
                        File.Delete(source);
                    }
                }
                else
                {
                    foreach (var tag in local.FavoriteTags)
                    {
                        if (tags.Contains(tag))
                        {
                            string source;
                            try
                            {
                                source = post.Download();
                            }
                            catch (WebException)
                            { continue; }
                            catch (InvalidDataException)
                            {
                                continue;
                            }
                            string dest;
                            if (!File.Exists(dest = Path.Combine(SavePath(post.Rating), tag, post.md5 + post.FileExtension)))
                            {
                                Log("Putting {0} into favorite folder {1}", post.md5, tag);
                                try
                                {
                                    //if (Path.GetDirectoryName(source) == Program.SavePath)
                                        File.Move(source, dest);
                                        break;
                                }
                                catch (WebException v)
                                {
                                    Log("Unable to download {0}.\n\t{1}", post.md5, v.Message);
                                }
                            }
                            else if (source != dest)
                            {
                                // Duplicate?
                                Log("Background: {0} exists in both {1} and {2}", post.id, source, dest);
                                File.Delete(source);
                            }
                        }
                    }
                    }
            }
        }
        static void Updater_ProgramUpdated(string OldVersion, string NewVersion)
        {
            //MessageBox.Show("Updated to version " + NewVersion);
            //new KonachanChanger.Forms.PropertyForm(Properties.Settings.Default).Show();
        }

        internal static string SavePath(string rating)
        {
            switch (rating)
            {
                case "s":
                    return LocalDb.GetInstance().Prefs.SavePathS;                    
                case "q":
                    return LocalDb.GetInstance().Prefs.SavePathQ;
                case "e":
                    return LocalDb.GetInstance().Prefs.SavePathE;
                default:
                    return LocalDb.GetInstance().Prefs.SavePathS;
            }
        }
    }
}